<?php

namespace App\Kuafu\Pay\Command;

use App\Kuafu\Pay\BasePay;
use App\Kuafu\Pay\Model\CheckFileModel;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Pay\Service\PayConfigService;
use App\Library\FeiShu\SendFs;
use App\Library\Zip\ZipOperate;
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Kuafu\File\FileUtil;

class GetCheckFile extends Command
{
    private string $errs = '';

    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'pay:get-check-file {date?} {fs?}';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = '获取各方对账文件';

    /**
     * Create a new command instance.
     *
     * @return void//
     */
    public function __construct()
    {
        parent::__construct();
    }

    /**
     * Execute the console command
     *
     * @return int
     */

    private string $date;
    private int    $intDate;

    public function handle()
    {
        ini_set('memory_limit', '-1');

        if ($this->argument('date')) {
            $this->date = date('Y-m-d', strtotime($this->argument('date')));
        } else {

            // 默认昨天
            $this->date = date('Y-m-d', time() - 86400);
        }
        $this->intDate = (int)date('Ymd', strtotime($this->date));

        if ($this->argument('fs')) {
            $fs = $this->argument('fs');
        } else {
            $fs = 1;
        }

        $companyLists = [
            PayConfigService::COMPANY_TJ_SUPPLER_CHAIN,
            PayConfigService::COMPANY_FRIED_IDEA,
            PayConfigService::COMPANY_DIGITAL_TECH,
        ];
        foreach ($companyLists as $company) {

            // 1.支付宝
            $this->ali($company);

            // 2.微信
            $this->wx($company);
        }

        if ($this->errs && $fs) {
            SendFs::newRobot(SendFs::ROBOT_CHECK)->setTitleContent('获取对账文件失败', $this->errs)->send();
        }

        // TODO 通知tiger
    }

    private function ali(int $company)
    {
        $companyName = PayConfigService::COMPANY_TEXT[$company] ?? $company;
        $payChannel  = PayStreamModel::PAY_CHANNEL_ALI;
        $api         = BasePay::instance($payChannel, 0, 0, $company)
                              ->downloadBill($this->date);

        if (!$api['status']) {

            Log::info("GetCheckFile err ali:", $api);

            // 没文件
            if ($api['code'] == 'isp.bill_not_exist') {

                // db也没记录
                if (!$this->payStreamCount($company, $payChannel)) {
                    return;
                }
            }

            $this->errs .= "{$this->date} 『{$companyName}』支付宝获取对账文件失败:{$api['msg']}" . PHP_EOL;
            return;
        }

        $url = $api['data']['url'];

        $params   = getQueryInUrl($url);

        $fileName = $params['downloadFileName'];
        $userId   = $params['partnerId'];
        $bizDates = $params['bizDates'];

        // 将zip下载到本地storage目录
        $response = (new Client([
            RequestOptions::TIMEOUT => 20,
            RequestOptions::VERIFY  => false
        ]))->get($url);
        Storage::put("/check/{$fileName}", $response->getBody());

        // 解压zip
        $zipPath   = storage_path("app/check/{$fileName}");
        $unZipPath = storage_path('app/check/' . $this->date);
        ZipOperate::unzip($zipPath, storage_path('app/check/' . $this->date));

        // 将解压后的csv上传至oss
        $csvPath = $unZipPath . "/{$userId}_{$bizDates}_业务明细.csv";
        $ossFile = FileUtil::uploadFile($csvPath, 'csv');
        Log::info("downloadBill payChannel:{$payChannel} company:{$company}", $ossFile);
        dump($ossFile);
        $path = $ossFile['path'];

        // 入库
        CheckFileModel::delData($this->intDate, $payChannel, $company);
        CheckFileModel::addData($this->intDate, $payChannel, $company, $path);

        // 删除本地文件
        Storage::delete("/check/{$fileName}");
        Storage::delete("/check/{$this->date}"); // TODO 目录没删成功
    }

    private function wx(int $company)
    {
        $companyName = PayConfigService::COMPANY_TEXT[$company] ?? $company;
        $payChannel  = PayStreamModel::PAY_CHANNEL_WX;
        $api         = BasePay::instance($payChannel, 0, 0, $company)
                              ->downloadBill($this->date);

        if (!$api['status']) {

            Log::info("GetCheckFile err wx:", $api);

            // 没文件
            if (strpos($api['msg'], 'NO_STATEMENT_EXIST') !== false) {

                // db也没记录
                if (!$this->payStreamCount($company, $payChannel)) {
                    return;
                }
            }

            $this->errs .= "{$this->date} 『{$companyName}』微信获取对账文件失败:{$api['msg']}" . PHP_EOL;
            return;
        }

        $url = $api['data']['url'];

        // 解密微信返回的csv
        $csvContent = BasePay::instance($payChannel, 0, 0, $company)->getDownloadFile($url, $this->date);
        $dateInt    = date('Ymd', strtotime($this->date));
        $putPath    = "/check/{$this->date}/{$company}_{$dateInt}_业务明细.csv";
        Storage::put($putPath, $csvContent);

        // 将csv上传至oss
        $csvPath = storage_path('app' . $putPath);
        $ossFile = FileUtil::uploadFile($csvPath, 'csv');
        Log::info("downloadBill payChannel:{$payChannel} company:{$company}", $ossFile);
        dump($ossFile);
        $path = $ossFile['path'];

        // 入库
        CheckFileModel::delData($this->intDate, $payChannel, $company);
        CheckFileModel::addData($this->intDate, $payChannel, $company, $path);

        // 删除本地文件
        Storage::delete($putPath);
    }

    private function payStreamCount(int $company, int $payChannel): int
    {
        // 接口没查到，但是DB有记录
        return PayStreamModel::suffix(null)
                             ->where('company', $company)
                             ->where('payChannel', $payChannel)
                             ->where('payStatus', PayStreamModel::PAY_STATUS_1)
                             ->whereBetween('createdAt', [strtotime($this->date), strtotime($this->date) + 86400 - 1])
                             ->count();
    }
}
